package com.csw.shuanfa.utils.id;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.security.SecureRandom;
import java.util.Random;

/**
 * @author 1
 * yYt9BF9qbdxo0XQmZsTf1
 * HoeMHgO8DWE49kfYkfp7L
 * xxPh6FgaBLXsYShFjKwL3
 * 277932次/s
 * 有字母（21位）    无序
 */
@Slf4j
@Component
public class NanoIdUtil {
    /**
     * 默认长度
     */
    public final int DEFAULT_SIZE = 21;
    /**
     * 默认随机数生成器，使用{@link SecureRandom}确保健壮性
     */
    private final SecureRandom DEFAULT_NUMBER_GENERATOR = getSecureRandom();

    /**
     * 默认随机字母表，使用URL安全的Base64字符
     */
    private final char[] DEFAULT_ALPHABET =
            "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();



    /**
     * 获取随机NanoId
     *
     * @return 随机NanoId
     * @since 5.7.5
     */
    public String getNanoId() {
        return randomNanoId();
    }


    /**
     * 获取SHA1PRNG的{@link SecureRandom}，类提供加密的强随机数生成器 (RNG)<br>
     * 注意：此方法获取的是伪随机序列发生器PRNG（pseudo-random number generator）
     *
     * <p>
     * 相关说明见：https://stackoverflow.com/questions/137212/how-to-solve-slow-java-securerandom
     *
     * @return {@link SecureRandom}
     */
    public SecureRandom getSecureRandom() {
        return createSecureRandom();
    }

    /**
     * 创建{@link SecureRandom}，类提供加密的强随机数生成器 (RNG)<br>
     *
     * @return {@link SecureRandom}
     * @since 4.6.5
     */
    public SecureRandom createSecureRandom() {
        return new SecureRandom();
    }

    /**
     * 生成伪随机的NanoId字符串，长度为默认的{@link #DEFAULT_SIZE}，使用密码安全的伪随机生成器
     *
     * @return 伪随机的NanoId字符串
     */
    public String randomNanoId() {
        return randomNanoId(DEFAULT_SIZE);
    }

    /**
     * 生成伪随机的NanoId字符串
     *
     * @param size ID长度
     * @return 伪随机的NanoId字符串
     */
    public String randomNanoId(int size) {
        return randomNanoId(null, null, size);
    }

    /**
     * 生成伪随机的NanoId字符串
     *
     * @param random   随机数生成器
     * @param alphabet 随机字母表
     * @param size     ID长度
     * @return 伪随机的NanoId字符串
     */
    public String randomNanoId(Random random, char[] alphabet, int size) {
        if (random == null) {
            random = DEFAULT_NUMBER_GENERATOR;
        }

        if (alphabet == null) {
            alphabet = DEFAULT_ALPHABET;
        }
        int minLength = 256;
        if (alphabet.length == 0 || alphabet.length >= minLength) {
            throw new IllegalArgumentException("Alphabet must contain between 1 and 255 symbols.");
        }

        if (size <= 0) {
            throw new IllegalArgumentException("Size must be greater than zero.");
        }
        int llk = alphabet.length - 1;
        final int mask = (2 << (int) Math.floor(Math.log(llk) / Math.log(2))) - 1;
        final int step = (int) Math.ceil(1.6 * mask * size / alphabet.length);

        final StringBuilder idBuilder = new StringBuilder();

        while (true) {
            final byte[] bytes = new byte[step];
            random.nextBytes(bytes);
            for (int i = 0; i < step; i++) {
                final int alphabetIndex = bytes[i] & mask;
                if (alphabetIndex < alphabet.length) {
                    idBuilder.append(alphabet[alphabetIndex]);
                    if (idBuilder.length() == size) {
                        return idBuilder.toString();
                    }
                }
            }
        }
    }
}
